package com.mars.common.web;


import com.ag.exception.CodeException;
import com.ag.exception.CommonCode;
import com.ag.utils.CollectionUtils;
import com.ag.utils.RequestUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;

import com.google.common.collect.Lists;
import com.mars.common.expetion.OrderStateException;
import com.mars.common.utils.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * title: ExceptionHandler.java 异常句柄
 *
 * @author rplees
 * @email rplees.i.ly@gmail.com
 * @version 1.0
 * @created 2015年9月16日 下午3:40:35
 */
public class ExceptionHandler implements HandlerExceptionResolver {
	final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());

	private Object prettyString(String s) {
		try {
			return JSON.parse(s);
		} catch(Exception ex) {
		}
		
		return s;
	}
	
	private ModelAndView mv(Object handler, Map<String, Object> map, HttpServletRequest request, Exception ex, boolean printStackTrace) {
		Object p = null;
		if("POST".equalsIgnoreCase(request.getMethod())) {//POST
			if(request instanceof ContentCachingRequestWrapper) {
				ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
				p = prettyString(new String(requestWrapper.getContentAsByteArray()));
			} else {
				p = RequestUtils.getPostParm(request);
			}
		} else {
			p = JSON.toJSON(request.getParameterMap());
		}

		// 记录logger
		String message = String.format("请求地址:%s>>>%s<<<,参数:%s, 异常信息:%s,请求头:%s",  request.getRequestURI(), request.getMethod(), p, ex.toString(), JSON.toJSONString(RequestUtils.getRequestHeaders(request)));
		logger.error(message,ex);
	//	PConstants.Loggers.EXCEPTION.error(message, printStackTrace ? ex : null);
		
		if(handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			boolean isResponseBody = handlerMethod.getMethod().isAnnotationPresent(ResponseBody.class)
					|| handlerMethod.getBeanType().isAnnotationPresent(RestController.class);
			
			if(isResponseBody) {
				return new ModelAndView(new FastJsonJsonView(), map);
			} else {
				return new ModelAndView("exception", map);
			}
		}
		return new ModelAndView(new FastJsonJsonView(), map);
	}

	public static CodeException getCodeException(Exception ex) {
		Throwable throwable = ex;
		
		while(throwable != null) {
			if(throwable instanceof CodeException) {
				return (CodeException) throwable;
			}
			
			throwable = throwable.getCause();
		}
		
		return null;
	}
	
	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		Map<String, Object> map = new HashMap<String, Object>();
		boolean printStackTrace = true;
		CodeException ce = getCodeException(ex);
		
		if(ex instanceof OrderStateException) {
			map = R.error(-1,((OrderStateException) ex).getMsg());
		} else if (ce != null) {// 自定义异常
			map = ce.toMap();
			printStackTrace = false;
		} else if(ex instanceof MissingServletRequestPartException) {
			map = R.error(-1,"请上传图片");
		} else if(ex instanceof HttpMessageNotReadableException) {
			map = R.error(-1,"无效的参数");
		} else if (ex instanceof SQLException || ex instanceof DataAccessException) {
			if(ex instanceof InvalidDataAccessApiUsageException) {
				InvalidDataAccessApiUsageException idaau = ((InvalidDataAccessApiUsageException) ex);
				if(idaau.getCause() != null && idaau.getCause() instanceof IllegalArgumentException) {
					map = R.error(-1, idaau.getCause().getLocalizedMessage());
					printStackTrace = false;
				} else {
					map = R.error(CommonCode.SQL_EXCEPTION, "哎呀，服务器出错啦！");
				}
			} else if(ex instanceof DataIntegrityViolationException) {//违法了唯一约束
				printStackTrace = false;
				map = R.error(CommonCode.SQL_EXCEPTION, "请稍后重试");
			} else {
				map = R.error(CommonCode.SQL_EXCEPTION, "哎呀，服务器出错啦！");
			}
		} else if (ex instanceof MultipartException) {
			map = R.error(CommonCode.FILE_UPLOAD_ERROR, "文件上传失败，切换网络试试！");
		} else if (ex instanceof NullPointerException) {
			map = R.error(CommonCode.NULL_POINT_ERROR, "，服务器出错啦！请稍后重试");
		} else if (ex instanceof ArrayIndexOutOfBoundsException) {
			map = R.error(CommonCode.ARRAY_INDEXOUTOF_BOUNDS, "哎呀，服务器出错啦！请稍后重试");
		} else {
			map = R.error(-1, ex.getLocalizedMessage());
		}
		
		// entry.value 不能为null
		List<String> nullKeyValueList = Lists.newArrayList();
		for(Map.Entry<String, Object> e : map.entrySet()) {
			if(e.getValue() == null) {
				nullKeyValueList.add(e.getKey());
			}
		}
		
		if(CollectionUtils.isNotEmpty(nullKeyValueList)) {
			for (String nukkKey : nullKeyValueList) {
				map.put(nukkKey, "null");
			}
		}
		
		return mv(handler, map, request, ex, printStackTrace);
	}
}
